<?php

namespace common\models\CommonModel;

use yii\db\ActiveQuery;
use common\components\DataHelper;
use common\models\User\User;
use yii\db\Connection;

Class CommonQuery extends ActiveQuery
{
    /**
     * 添加未被删除条件
     * 自动判断是否有软删除字段
     * @param $obj
     * @param $delField
     * @param $delValue
     * @return $this
     */
	public function notDel($obj, $delField, $delValue)
	{   
		$arrAttr = $obj->attributes();

 		if ( in_array($delField, $arrAttr) )
 		{
 		    $this->andWhere([
 		        "and",
 		        ["=", $delField, $delValue]
            ]);
 		}
 		
 		return $this;
	}
	
    public function unSelect($attribute)
    {
        if ( !is_array($attribute) ) {
            $attribute = explode(",", $attribute);
        }
        $model = new $this->modelClass;
        $attributes = $model->getAttributes();
        $attributes = array_keys($attributes);
        $attributes = array_diff($attributes, $attribute);
        return $this->select($attributes);
    }

    /**
     * @param $pk
     * for update 锁 这里不保证where中是否有主键或唯一索引 也不保证被锁行是否已被求情加锁 需要开发者自己注意
     * @return array|\yii\db\ActiveRecord[]
     */
    public function lockForUpdateAll($pk = "id")
    {
        if ($this->modelClass::getDb()->getTransaction() === null) {
            throw new \BadMethodCallException('Active transaction is required');
        }

        $this->sql = $this->createCommand()->getRawSql() . " for update";
        $ret = $this->all();
        //标记已经被锁 这里的标记是方便其他方法加锁时可以获取对应的数据是否加锁 但本方法并不检查
        if ( $ret ) {
            $model = new $this->modelClass;
            $pkValues = [];
            foreach ( $ret as $item ) {
                $pkValues[] = $item[$pk];
                $model->setIsForUpdate(true, $item[$pk]);
            }
            $this->modelClass::getDb()->on(Connection::EVENT_COMMIT_TRANSACTION, function($e) use ($pkValues, $model){
                foreach ( $pkValues as $pk ) {
                    $model->setIsForUpdate(false, $pk);
                }
                $this->modelClass::getDb()->off(Connection::EVENT_COMMIT_TRANSACTION);
                $this->modelClass::getDb()->off(Connection::EVENT_ROLLBACK_TRANSACTION);
            }, $this);
            $this->modelClass::getDb()->on(Connection::EVENT_ROLLBACK_TRANSACTION, function($e)use ($pkValues, $model){
                foreach ( $pkValues as $pk ) {
                    $model->setIsForUpdate(false, $pk);
                }
                $this->modelClass::getDb()->off(Connection::EVENT_COMMIT_TRANSACTION);
                $this->modelClass::getDb()->off(Connection::EVENT_ROLLBACK_TRANSACTION);
            }, $this);
        }
        return $ret;
    }

    /**
     * @param $pk
     * @return array|null|\yii\db\ActiveRecord
     */
    public function lockForUpdateOne($pk = "id")
    {
        if ($this->modelClass::getDb()->getTransaction() === null) {
            throw new \BadMethodCallException('Active transaction is required');
        }
        $this->sql = $this->createCommand()->getRawSql() . " for update";
        $ret = $this->one();
        //标记已经被锁
        if ( $ret ) {
            $model = new $this->modelClass;
            $model->setIsForUpdate(true, $ret[$pk]);
            $pkValue = $ret[$pk];
            $this->modelClass::getDb()->on(Connection::EVENT_COMMIT_TRANSACTION, function($e) use ($pkValue, $model){
                $model->setIsForUpdate(false, $pkValue);
                $this->modelClass::getDb()->off(Connection::EVENT_COMMIT_TRANSACTION);
                $this->modelClass::getDb()->off(Connection::EVENT_ROLLBACK_TRANSACTION);
            }, $this);
            $this->modelClass::getDb()->on(Connection::EVENT_ROLLBACK_TRANSACTION, function($e) use ($pkValue, $model){
                $model->setIsForUpdate(false, $pkValue);
                $this->modelClass::getDb()->off(Connection::EVENT_COMMIT_TRANSACTION);
                $this->modelClass::getDb()->off(Connection::EVENT_ROLLBACK_TRANSACTION);
            }, $this);
        }
        return $ret;
    }
}